home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_100
/
182_01
/
sb_217.c
< prev
next >
Wrap
Text File
|
1990-07-30
|
14KB
|
639 lines
#define VERSION "sb 2.17 07-02-85"
#define PUBDIR "/usr/spool/uucppublic"
/*% cc -O -DUSG sb.c -o sb
* sb.c By Chuck Forsberg
*
* A small program for Unix which can send 1 or more
* files in Batch mode to computers running YAM. (Use "rb" in YAM.)
* Supports the CRC option or regular checksum.
* Exit status is 0 for all transfers completed successfully,
* 1 for 1 or more unreadable files or'd with 200 for incomplete file xfer.
*
* accepts -k option for 1kb record length.
*
* sb is derived from yam2.c
* Uses buffered i/o to reduce the CPU time compared to UMODEM.
* USG UNIX (3.0) ioctl conventions courtesy Jeff Martin
* cc -O -DV7 sb.c -o sb vanilla Unix version 7
* cc -O -DUSG sb.c -o sb USG (3.0) Unix
* ******* Some systems (Venix, Coherent, Regulus) do not *******
* ******* support tty raw mode read(2) identically to *******
* ******* Unix. ONEREAD must be defined to force one *******
* ******* character reads for these systems. *******
*/
#define LOGFILE "/tmp/sblog"
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <ctype.h>
#define PATHLEN 256
#define OK 0
#define FALSE 0
#define TRUE 1
#define ERROR (-1)
#define HOWMANY 2
#include "rbsb.c" /* most of the system dependent stuff here */
FILE *in;
/* Ward Christensen / CP/M parameters - Don't change these! */
#define ENQ 005
#define CAN ('X'&037)
#define XOFF ('s'&037)
#define XON ('q'&037)
#define SOH 1
#define STX 2
#define EOT 4
#define ACK 6
#define NAK 025
#define CPMEOF 032
#define WANTCRC 0103 /* send C not NAK to get crc not checksum */
#define WANTG 0107 /* Send G not NAK to get nonstop batch xmsn */
#define TIMEOUT (-2)
#define ERRORMAX 5
#define RETRYMAX 5
#define SECSIZ 128 /* cp/m's Magic Number record size */
#define KSIZE 1024
char Lastrx;
char Crcflg;
int Wcsmask=0377;
int Verbose=0;
int Restricted=0; /* restricted; no /.. or ../ in filenames */
int Quiet=0; /* overrides logic that would otherwise set verbose */
int Fullname=0; /* transmit full pathname */
int Unlinkafter=0; /* Unlink file after it is sent */
int Dottoslash=0; /* Change foo.bar.baz to foo/bar/baz */
int firstsec;
int errcnt=0; /* number of files unreadable */
int blklen=SECSIZ; /* length of transmitted records */
int Optiong; /* Let it rip no wait for sector ACK's */
int Noeofseen;
int Totsecs; /* total number of sectors this file */
char txbuf[KSIZE];
int Filcnt=0; /* count of number of files opened */
jmp_buf tohere; /* For the interrupt on RX timeout */
unsigned updcrc();
char *substr(), *getenv();
/* called by signal interrupt or terminate to clean things up */
bibi(n)
{
canit(); fflush(stdout); mode(0);
fprintf(stderr, "sb: caught signal %d; exiting\n", n);
if (n == SIGQUIT)
abort();
exit(128+n);
}
#ifdef REGULUS
sendline(c)
{
static char d[2];
d[0] = c&Wcsmask;
write(1, d, 1);
}
#else
#define sendline(c) putchar(c & Wcsmask)
#endif
main(argc, argv)
char *argv[];
{
register char *cp;
register npats;
int agcnt; char **agcv;
char **patts;
int exitcode;
#ifndef REGULUS
static char xXbuf[BUFSIZ];
#endif
if ((cp=getenv("SHELL")) && substr(cp, "rsh"))
Restricted=TRUE;
npats=0;
if (argc<2)
goto usage;
#ifndef REGULUS
setbuf(stdout, xXbuf);
#endif
while (--argc) {
cp = *++argv;
if (*cp == '-') {
while ( *++cp) {
switch(*cp) {
case '1':
iofd = 1; break;
case '7':
Wcsmask=0177; break;
case 'd':
++Dottoslash;
/* **** FALL THROUGH TO **** */
case 'f':
Fullname=TRUE; break;
case 'k':
blklen=KSIZE; break;
case 'q':
Quiet=TRUE; Verbose=0; break;
case 'u':
++Unlinkafter; break;
case 'v':
++Verbose; break;
default:
goto usage;
}
}
}
else if ( !npats && argc>0) {
if (argv[0][0]) {
npats=argc;
patts=argv;
}
}
}
if (npats < 1) {
usage:
fprintf(stderr,"%s by Chuck Forsberg\n", VERSION);
fprintf(stderr,"Usage: sb [-7dfkquv] file ...\n");
exit(1);
}
if (Verbose) {
if (freopen(LOGFILE, "a", stderr)==NULL) {
printf("Can't open log file %s\n",LOGFILE);
exit(0200);
}
setbuf(stderr, NULL);
}
if (fromcu() && !Quiet) {
if (Verbose == 0)
Verbose = 2;
}
if (Verbose != 1) {
fprintf(stderr, "sb: %d file%s requested:\r\n",
npats, npats>1?"s":"");
for ( agcnt=npats, agcv=patts; --agcnt>=0; ) {
fprintf(stderr, "%s ", *agcv++);
}
}
mode(1);
if (signal(SIGINT, bibi) == SIG_IGN) {
signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
}
else {
signal(SIGINT, bibi); signal(SIGKILL, bibi);
signal(SIGQUIT, bibi);
}
if (wcsend(npats, patts)==ERROR) {
exitcode=0200;
canit();
}
fflush(stdout);
mode(0);
exit((errcnt != 0) | exitcode);
}
wcsend(argc, argp)
char *argp[];
{
register n;
Crcflg=FALSE;
firstsec=TRUE;
for (n=0; n<argc; ++n) {
Totsecs = 0;
if (wcs(argp[n])==ERROR)
goto fubar;
}
Totsecs = 0;
if (Filcnt==0) { /* bitch if we couldn't open ANY files */
fprintf(stderr,"\r\nCan't open any requested files.\n");
return ERROR;
}
else if (wctxpn("")==ERROR)
goto fubar;
return OK;
fubar:
canit(); return ERROR;
}
wcs(oname)
char *oname;
{
register c;
register char *p;
struct stat f;
char name[PATHLEN];
strcpy(name, oname);
if (Restricted) {
/* restrict pathnames to current tree or uucppublic */
if ( substr(name, "../")
|| (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
canit();
fprintf(stderr,"\r\nsb:\tSecurity Violation\r\n");
return ERROR;
}
}
if ((in=fopen(oname, "r"))==NULL) {
++errcnt;
return OK; /* pass over it, there may be others */
}
++Noeofseen;
/* Check for directory or block special files */
#ifndef REGULUS /* This doesn't seem to work on Regulus */
fstat(fileno(in), &f);
c = f.st_mode & S_IFMT;
if (c == S_IFDIR || c == S_IFBLK) {
fclose(in);
return OK;
}
#endif
++Filcnt;
if (wctxpn(name)== ERROR)
return ERROR;
if (wctx()==ERROR)
return ERROR;
if (Unlinkafter)
unlink(oname);
return 0;
}
/*
* generate and transmit pathname block consisting of
* pathname (null terminated),
* file length, mode time and file mode in octal
* as provided by the Unix fstat call.
* N.B.: modifies the passed name, may extend it!
*/
wctxpn(name)
char *name;
{
register firstch;
register char *p, *q;
char name2[PATHLEN];
struct stat f;
logent("\r\nAwaiting pathname nak for %s\r\n", *name?name:"<END>");
if (getnak())
return ERROR;
q = (char *) 0;
if (Dottoslash) { /* change . to . */
for (p=name; *p; ++p) {
if (*p == '/')
q = p;
else if (*p == '.')
*(q=p) = '/';
}
if (q && strlen(++q) > 8) { /* If name>8 chars */
q += 8; /* make it .ext */
strcpy(name2, q); /* save excess of name */
*q = '.';
strcpy(++q, name2); /* add it back */
}
}
for (p=name, q=txbuf ; *p; )
if ((*q++ = *p++) == '/' && !Fullname)
q = txbuf;
*q++ = 0;
p=q;
while (q < (txbuf + KSIZE))
*q++ = 0;
#ifndef REGULUS /* This doesn't seem to work on Regulus */
if (*name && fstat(fileno(in), &f)!= -1)
sprintf(p, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode);
#endif
/* force 1k blocks if name won't fit in 128 byte block */
if (strlen(txbuf) > 127)
blklen=KSIZE;
if (wcputsec(txbuf, 0, SECSIZ)==ERROR)
return ERROR;
return OK;
}
getnak()
{
register firstch;
Lastrx = 0;
for (;;) {
switch (firstch = readock(800,2)) {
case TIMEOUT:
logent("Timeout on pathname\n");
return TRUE;
case WANTG:
mode(2); /* Set cbreak, XON/XOFF, etc. */
Optiong = TRUE;
case WANTCRC:
Crcflg = TRUE;
case NAK:
return FALSE;
case CAN:
if (Lastrx == CAN)
return TRUE;
default:
break;
}
Lastrx = firstch;
}
}
wctx()
{
register int sectnum, attempts, firstch;
firstsec=TRUE;
while ((firstch=readock(400, 2))!=NAK && firstch != WANTCRC
&& firstch!=TIMEOUT